package org.rowan.adi.components.comp2d.polygon;

import java.util.LinkedList;
import org.rowan.adi.Vector;
import org.rowan.adi.components.comp2d.Component2D;
import org.rowan.adi.components.comp2d.LineSegment2D;
import org.rowan.adi.components.comp2d.Point2D;
import org.rowan.adi.linearalgebra.LinearAlgebra2D;
import org.rowan.adi.components.comp2d.Circle;

/**
 * The Polygon class generalizes all polygons in two dimensional space.
 *
 * @author Robert Russell
 * @version 1.0
 */
public abstract class Polygon extends Component2D {

    /**
     * Computes the area of the 2D shape.
     * @return the area of the 2D shape.
     */
    public abstract double computeArea();

    /**
     * Gets the bounding box, or the minimum-area enclosing rectangle, for this Polygon.
     * @return an instance of Rectangle, which represents the bounding box, or the
     * mininum-area enclosing rectangle, for this Polygon.
     */
    public Rectangle getBoundingBox() {
        LinkedList<Point2D> points = super.getListofPoints();
        return Polygon.getBoundingBox(points);
    }

    /**
     * Gets the bounding box, or the minimum-area enclosing rectangle, for the list of points.
     * @return an instance of Rectangle, which represents the bounding box, or the
     * mininum-area enclosing rectangle, for the list of points.
     */
    public static Rectangle getBoundingBox(LinkedList<Point2D> points) {
        if (points.size() == 0) {
            throw new IllegalArgumentException("The list of points is empty.");
        }
        double bottomLeftX = points.get(0).getX();
        double bottomLeftY = points.get(0).getY();
        double upperRightX = points.get(0).getX();
        double upperRightY = points.get(0).getY();

        // Determine the lowest X and Y values for the bottom left point of the
        // bounding box and the highest X and Y values for the upper right point
        // of the bounding box.
        for (Point2D point : points) {
            if (point.getX() < bottomLeftX) {
                bottomLeftX = point.getX();
            }

            if (point.getY() < bottomLeftY) {
                bottomLeftY = point.getY();
            }

            if (point.getX() > upperRightX) {
                upperRightX = point.getX();
            }

            if (point.getY() > upperRightY) {
                upperRightY = point.getY();
            }
        }

        // Create the two points found, plus the upper left point based on the
        // the two other points. These points are needed in order to easily compute
        // the width and length of the bounding box. The line segment is used to
        // easily compute the center point of the bounding box so the instance of
        // Rectangle can be created.
        Point2D bottomLeft = new Point2D(new Vector(bottomLeftX, bottomLeftY));
        Point2D upperLeft = new Point2D(new Vector(bottomLeftX, upperRightY));
        Point2D upperRight = new Point2D(new Vector(upperRightX, upperRightY));
        LineSegment2D segment = new LineSegment2D(bottomLeft, upperRight);
        double length = LinearAlgebra2D.distance(bottomLeft, upperLeft);
        double width = LinearAlgebra2D.distance(upperLeft, upperRight);

        return new Rectangle(segment.getLocation(), width, length);
    }

    /**
     * Computes the cross-sectional area of this Polygon with the Circle instance given.
     * @param circle an instance of Circle.
     * @return the cross-sectional area of this Polygon with the Circle instance given.
     */
    public final double intersectCircle(Circle circle) {
        return LinearAlgebra2D.intersectArea(circle, this);
    }
}
